/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package ca.trader.user;

import ca.trader.comment.Comment;
import ca.trader.db.UserTableConstraints;
import ca.trader.regions.Country;
import ca.trader.regions.Location;
import ca.trader.regions.Region;
import ca.trader.sale.Sale;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Embedded;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.ManyToMany;
import javax.persistence.NamedQueries;
import javax.persistence.NamedQuery;
import javax.persistence.OneToMany;
import javax.persistence.SequenceGenerator;
import javax.persistence.Transient;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlTransient;
import org.eclipse.persistence.annotations.Index;

/**
 * Entity bean for representing a user
 * @author Ahsan
 */
@Entity
@NamedQueries(
{
	 // Query for finding a user by email address
	 @NamedQuery(name = UserEntityConsts.NAMED_QUERY_FIND_USER_BY_EMAIL,
	 query = "SELECT u FROM User u WHERE u.email = :" + UserEntityConsts.NAMED_QUERY_FIND_USER_BY_EMAIL_PARAM_EMAIL)
})
@XmlRootElement
public class User implements Serializable
{

	 /**
	  * The id of the user.  Auto-generated.  Should not be set manually.
	  */
	 @Column(length = UserTableConstraints.CONSTRAINT_ID_MAX_LENGTH, nullable = false)
	 @Id
	 @SequenceGenerator(name = "USER_ID_SEQ", allocationSize = 1, initialValue = 1)
	 @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "USER_ID_SEQ")
	 private Integer id;
	 
	 /**
	  * The last name of the user
	  */
	 @Column(length = UserTableConstraints.CONSTRAINT_LAST_NAME_MAX_LENGTH, nullable = false)
	 private String lastName;
	 
	 /**
	  * The first name of the user
	  */
	 @Column(length = UserTableConstraints.CONSTRAINT_FIRST_NAME_MAX_LENGTH, nullable = false)
	 private String firstName;
	 
	 /**
	  * The email address of the user
	  */
	 @Index(unique=true) 
	 @Column(length = UserTableConstraints.CONSTRAINT_EMAIL_MAX_LENGTH, nullable = false, unique = true)
	 private String email;
	 
	 /**
	  * The location of the user
	  */
	 @Embedded
	 private Location location;
	 
	 /**
	  * Whether the user is activated or not.  0 for not activated, 1 for activated.
	  * The user activation feature is currently not fully implemented, so this field is always set to 1.
	  */
	 @Column(length = 1, nullable = false)
	 private byte activated = 0;
	 
	 /**
	  * The crypted password of the user.
	  */
	 @Column(length = UserTableConstraints.CONSTRAINT_PASSWORD_MAX_LENGTH, nullable = false)
	 private String cryptedPassword;
	 
	 @ManyToMany ( cascade ={
		  CascadeType.MERGE, CascadeType.REFRESH
	 }, fetch = FetchType.LAZY)
	 private List<Sale> favouriteSales = new ArrayList<>();

	 
	 @OneToMany (mappedBy = "commentor", cascade =
	 {
		  CascadeType.MERGE, CascadeType.REFRESH
	 }, fetch = FetchType.LAZY)	 
	 private List<Comment> commentList = new ArrayList <>();
	 /**
	  * Get ths crypted password of the user
	  * @return the crypted password
	  */
	 public String getCryptedPassword()
	 {
		  return cryptedPassword;
	 }

	 /**
	  * Set the crypted password of the user
	  * @param cryptedPassword the crypted password
	  */
	 public void setCryptedPassword(String cryptedPassword)
	 {
		  this.cryptedPassword = cryptedPassword;
	 }

	 /**
	  * If the user is activated
	  * @return if the user ia activated
	  */
	 public boolean isActivated()
	 {
		  return activated != 0;
	 }

	 /**
	  * Sets the user activated or not
	  * @param activated whether the user should be set activated.  true for activated. false for not activated.
	  */
	 public void setActivated(boolean activated)
	 {
		  this.activated = activated ? (byte) 1 : (byte) 0;
	 }

	 /**
	  * Gets the id of the user. 
	  * @return the id of the user
	  */
	 public Integer getId()
	 {
		  return id;
	 }

	 /**
	  * Gets the last name of the user
	  * @return last of the user
	  */
	 public String getLastName()
	 {
		  return lastName;
	 }

	 /**
	  * Sets the last name of the user
	  * @param lastName last name of the user
	  */
	 public void setLastName(String lastName)
	 {
		  this.lastName = lastName;
	 }

	 /**
	  * Gets the first name of the user
	  * @return the first name of the user
	  */
	 public String getFirstName()
	 {
		  return firstName;
	 }

	 /**
	  * Sets the first name of the user
	  * @param firstName the first name of the user
	  */
	 public void setFirstName(String firstName)
	 {
		  this.firstName = firstName;
	 }

	 /**
	  * Gets the email of the user
	  * @return the email of the user
	  */
	 public String getEmail()
	 {
		  return email;
	 }

	 /**
	  * Sets the email of the user
	  * @param email the email of the user
	  */
	 public void setEmail(String email)
	 {
		  this.email = email;
	 }

	 /**
	  * Gets the location of the user
	  * @return the location of the user
	  */
	 public Location getLocation()
	 {
		  return location;
	 }

	 /**
	  * Sets the location of the user
	  * @param location the location of the user
	  */
	 public void setLocation(Location location)
	 {
		  this.location = location;
	 }

	 /**
	  * Gets the country of the user
	  * @return the country of the user
	  */
	 @Transient
	 public Country getCountry()
	 {
		  return location.getCountry();
	 }

	 /**
	  * Gets the region of the user
	  * @return the region of the user
	  */
	 @Transient
	 public Region getRegion()
	 {
		  return location.getRegion();
	 }

	 /**
	  * Gets the city of the user
	  * @return city of the user
	  */
	 @Transient
	 public String getCity()
	 {
		  return location.getCity();
	 }
	 
	 @Transient
	 @Override
	 public boolean equals (Object obj)
	 {
		  if (!(obj instanceof User))
		  {
			   return false;
		  }
		  
		  return this.getId().equals(((User) obj).getId());
	 }
	 
	 @Override
	 public String toString()
	 {
		  return firstName + " " + lastName;
	 }
	 
	 public void addFavouriteSale (Sale sale)
	 {
		  if (sale != null)
		  {
			   favouriteSales.add(sale);
		  }
		  else
		  {
			   throw new IllegalArgumentException ("Sale object is null!");
		  }
	 }
	 
	 @XmlTransient
	 public List<Sale> getFavouriteSales()
	 {
		  return Collections.unmodifiableList(favouriteSales);
	 }
	 
	 @XmlTransient
	 public List<Comment> getCommentList()
	 {
		  return Collections.unmodifiableList(commentList);
	 }
	 
	 public boolean isSaleFavourited (Sale sale)
	 {
		  return favouriteSales.contains(sale);
	 }
	 
	 public void unfavouriteSale (Sale sale)
	 {
		  if (sale != null)
		  {
			   favouriteSales.remove(sale);
		  }
		  else
		  {
			   throw new IllegalArgumentException ("Sale object is null!");
		  }
	 }

	 public void addComment (Comment comment)
	 {
		  if (comment != null)
		  {
			   commentList.add(comment);
		  }
		  else
		  {
			   throw new IllegalArgumentException ("comment object is null!");
		  }
	 }
}
